package cn.steam.foo.config.logback;

import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhang jintao on 2022/05/20
 **/
public class SensitiveConvert extends MessageConverter {

    @Override
    public String convert(ILoggingEvent event) {

        Object[] args = event.getArgumentArray();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                // 偷天换日
                args[i] = desensitization(args[i]);
            }
            return MessageFormatter.arrayFormat(event.getMessage(), args).getMessage();
        }

        return event.getFormattedMessage();
    }

    /**
     * 对字段进行脱敏
     */
    private Object desensitization(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            Class<?> clazz = obj.getClass();
            if (List.class.isAssignableFrom(clazz)) {
                return fakeList((List<?>) obj);
            }
            if (Map.class.isAssignableFrom(clazz)) {
                return fakeMap((Map<?, ?>) obj);
            }
            return fakeObj(obj);
        } catch (Exception e) {
            System.out.println("脱敏失败：" + e);
            return obj;
        }
    }


    private Object fakeMap(Map<?, ?> obj) {

        return obj;
    }

    private Object fakeObj(Object obj) throws InstantiationException, IllegalAccessException {
        Class<?> clazz = obj.getClass();
        if (!clazz.getName().startsWith("cn.steam")) {
            return obj;
        }

        List<Field> fields = getCaseFields(clazz);
        if (CollectionUtils.isEmpty(fields)) {
            return obj;
        }

        Object fake = clazz.newInstance();
        BeanUtils.copyProperties(obj, fake);
        for (Field field : fields) {
            field.setAccessible(true);
            field.set(fake, "敏****感");
        }
        return fake;

    }

    private Object fakeList(List<?> list) throws InstantiationException, IllegalAccessException {
        // 替换集合
        if (CollectionUtils.isEmpty(list)) {
            return list;
        }
        if (CollectionUtils.isEmpty(getCaseFields(list.get(0).getClass()))) {
            return list;
        }
        List<Object> fake = new ArrayList<>();
        for (Object o : list) {
            fake.add(fakeObj(o));
        }
        return fake;
    }

    private List<Field> getCaseFields(Class<?> clazz) {
        return Arrays.stream(clazz.getDeclaredFields())
                .filter(f -> f.isAnnotationPresent(Sensitive.class)).collect(Collectors.toList());
    }

}
